home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / bin / kibitz < prev    next >
Text File  |  1995-07-21  |  10KB  |  404 lines

  1. #!/usr/skunk/bin/expect --
  2. # allow another user to share a shell (or other program) with you
  3. # See kibitz(1) man page for complete info.
  4. # Author: Don Libes, NIST
  5. # Date written: December 5, 1991
  6. # Date last editted: October 19, 1994
  7. # Version: 2.11
  8. exp_version -exit 5.0
  9.  
  10. # if environment variable "EXPECT_PROMPT" exists, it is taken as a regular
  11. # expression which matches the end of your login prompt (but does not other-
  12. # wise occur while logging in).
  13.  
  14. set prompt "(%|#|\\$) $"    ;# default prompt
  15. set noproc 0
  16. set tty ""            ;# default if no -tty flag
  17. set allow_escape 1        ;# allow escapes if true
  18. set escape_char \035        ;# control-right-bracket
  19. set escape_printable "^\]"
  20. set verbose 1            ;# if true, describe what kibitz is doing
  21.  
  22. set kibitz "kibitz"        ;# where kibitz lives if some unusual place.
  23.                 ;# this must end in "kibitz", but can have
  24.                 ;# things in front (like directory names).
  25. #set proxy "kibitz"        ;# uncomment and set if you want kibitz to use
  26.                 ;# some other account on remote systems
  27.  
  28. # The following code attempts to intuit whether cat buffers by default.
  29. # The -u flag is required on HPUX (8 and 9) and IBM AIX (3.2) systems.
  30. if [file exists $exp_exec_library/cat-buffers] {
  31.     set catflags "-u"
  32. } else {
  33.     set catflags ""
  34. }
  35. # If this fails, you can also force it by commenting in one of the following.
  36. # Or, you can use the -catu flag to the script.
  37. #set catflags ""
  38. #set catflags "-u"
  39.  
  40. # Some flags must be passed onto the remote kibitz process.  They are stored
  41. # in "kibitz_flags".  Currently, they include -tty and -silent.
  42. set kibitz_flags ""
  43.  
  44. while {[llength $argv]>0} {
  45.     set flag [lindex $argv 0]
  46.     switch -- $flag \
  47.     "-noproc" {
  48.         set noproc 1
  49.         set argv [lrange $argv 1 end]
  50.     } "-catu" {
  51.         set catflags "-u"
  52.         set argv [lrange $argv 1 end]
  53.     } "-tty" {
  54.         set tty [lindex $argv 1]
  55.         set argv [lrange $argv 2 end]
  56.         set kibitz_flags "$kibitz_flags -tty $tty"
  57.     } "-noescape" {
  58.         set allow_escape 0
  59.         set argv [lrange $argv 1 end]
  60.     } "-escape" {
  61.         set escape_char [lindex $argv 1]
  62.         set escape_printable $escape_char
  63.         set argv [lrange $argv 2 end]
  64.     } "-silent" {
  65.         set verbose 0
  66.         set argv [lrange $argv 1 end]
  67.         set kibitz_flags "$kibitz_flags -silent"
  68.     } "-proxy" {
  69.         set proxy [lindex $argv 1]
  70.         set argv [lrange $argv 2 end]
  71.     } default {
  72.         break
  73.     }
  74. }
  75.  
  76. if {([llength $argv]<1) && ($noproc==0)} {
  77.     send_user "usage: kibitz \[args] user \[program ...]\n"
  78.     send_user "   or: kibitz \[args] user@host \[program ...]\n"
  79.     exit
  80. }
  81.  
  82. log_user 0
  83. set timeout -1
  84.  
  85. set user [lindex $argv 0]
  86. if [string match -r $user] {
  87.     send_user "KRUN"    ;# this tells user_number 1 that we're running
  88.                 ;# and to prepare for possible error messages
  89.     set user_number 3
  90.     # need to check that it exists first!
  91.     set user [lindex $argv 1]
  92. } else {
  93.     set user_number [expr 1+(0==[string first - $user])]
  94. }
  95.  
  96. # at this point, user_number and user are correctly determined
  97. # User who originated kibitz session has user_number == 1 on local machine.
  98. # User who is responding to kibitz has user_number == 2.
  99. # User who originated kibitz session has user_number == 3 on remote machine.
  100.  
  101. # user 1 invokes kibitz as "kibitz user[@host]"
  102. # user 2 invokes kibitz as "kibitz -####" (some pid).
  103. # user 3 invokes kibitz as "kibitz -r user".
  104.  
  105. # uncomment for debugging: leaves each user's session in a file: 1, 2 or 3
  106. #exec rm -f $user_number
  107. #exp_internal -f $user_number 0
  108.  
  109. set user2_islocal 1    ;# assume local at first
  110.  
  111. # later move inside following if $user_number == 1
  112. # return true if x is a prefix of xjunk, given that prefixes are only
  113. # valid at . delimiters
  114. # if !do_if0, skip the whole thing - this is here just to make caller simpler
  115. proc is_prefix {do_if0 x xjunk} {
  116.     if 0!=$do_if0 {return 0}
  117.     set split [split $xjunk .]
  118.     for {set i [expr [llength $split]-1]} {$i>=0} {incr i -1} {
  119.         if [string match $x [join [lrange $split 0 $i] .]] {return 1}
  120.     }
  121.     return 0
  122. }
  123.  
  124. # get domainname.  Unfortunately, on some systems, domainname(1)
  125. # returns NIS domainname which is not the internet domainname.
  126. proc domainname {} {
  127.     # open pops stack upon failure
  128.     set rc [catch {open /etc/resolv.conf r} file]
  129.     if {$rc==0} {
  130.         while {-1!=[gets $file buf]} {
  131.             if 1==[scan $buf "domain %s" name] {
  132.                 close $file
  133.                 return $name
  134.             }
  135.         }
  136.         close $file
  137.     }
  138.  
  139.     # fall back to using domainname
  140.     if {0==[catch {exec domainname} name]} {return $name}
  141.  
  142.     error "could not figure out domainname"
  143. }
  144.  
  145. if $user_number==1 {
  146.     if $noproc==0 {
  147.         if [llength $argv]>1 {
  148.             set pid [eval spawn [lrange $argv 1 end]]
  149.         } else {
  150.             set pid [spawn $env(SHELL)]
  151.         }
  152.         set shell $spawn_id
  153.     }
  154.  
  155.     # is user2 remote?
  156.     regexp (\[^@\]*)@*(.*) $user ignore tmp host
  157.     set user $tmp
  158.     if ![string match $host ""] {
  159.         set h_rc [catch {exec hostname}    hostname]
  160.         set d_rc [catch domainname     domainname]
  161.  
  162.         if {![is_prefix $h_rc $host $hostname]
  163.          && ![is_prefix $d_rc $host $hostname.$domainname]} {
  164.             set user2_islocal 0
  165.         }
  166.     }
  167.  
  168.     if !$user2_islocal {
  169.         if $verbose {send_user "connecting to $host\n"}
  170.  
  171.         if ![info exists proxy] {
  172.             proc whoami {} {
  173.                 global env
  174.                 if [info exists env(USER)] {return $env(USER)}
  175.                 if [info exists env(LOGNAME)] {return $env(LOGNAME)}
  176.                 if ![catch {exec whoami} user] {return $user}
  177.                 if ![catch {exec logname} user] {return $user}
  178.                 # error "can't figure out who you are!"
  179.             }
  180.             set proxy [whoami]
  181.         }
  182.         spawn rlogin $host -l $proxy -8
  183.         set userin $spawn_id
  184.         set userout $spawn_id
  185.  
  186.         catch {set prompt $env(EXPECT_PROMPT)}
  187.  
  188.         set timeout 120
  189.         expect {
  190.             assword: {
  191.                 stty -echo
  192.                 send_user "password (for $proxy) on $host: "
  193.                 set old_timeout $timeout; set timeout -1
  194.                 expect_user -re "(.*)\n"
  195.                 send_user "\n"
  196.                 set timeout $old_timeout
  197.                 send "$expect_out(1,string)\r"
  198.                 # bother resetting echo?
  199.                 exp_continue
  200.             } incorrect* {
  201.                 send_user "invalid password or account\n"
  202.                 exit
  203.             } "TERM = *) " {
  204.                 send "\r"
  205.                 exp_continue
  206.             } timeout {
  207.                 send_user "connection to $host timed out\n"
  208.                 exit
  209.             } eof {
  210.                 send_user "connection to host failed: $expect_out(buffer)"
  211.                 exit
  212.             } -re $prompt
  213.         }
  214.         if $verbose {send_user "starting kibitz on $host\n"}
  215.         # the kill protects user1 from receiving user3's
  216.         # prompt if user2 exits via expect's exit.
  217.         send "$kibitz $kibitz_flags -r $user;kill -9 $$\r"
  218.  
  219.         expect {
  220.             -re "kibitz $kibitz_flags -r $user.*KRUN" {}
  221.             -re "kibitz $kibitz_flags -r $user.*(kibitz\[^\r\]*)\r" {
  222.                 send_user "unable to start kibitz on $host: \"$expect_out(1,string)\"\n"
  223.                 send_user "try rlogin by hand followed by \"kibitz $user\"\n"
  224.                 exit
  225.             }
  226.             timeout {
  227.                 send_user "unable to start kibitz on $host: "
  228.                 set expect_out(buffer) "timed out"
  229.                 set timeout 0; expect -re .+
  230.                 send_user $expect_out(buffer)
  231.                 exit
  232.             }
  233.         }
  234.         expect {
  235.             -re ".*\n" {
  236.                 # pass back diagnostics
  237.                 # should really strip out extra cr
  238.                 send_user $expect_out(buffer)
  239.                 exp_continue
  240.             }
  241.             KABORT exit
  242.             default exit
  243.             KDATA
  244.         }
  245.     }
  246. }
  247.  
  248. if $user_number==2 {
  249.     set pid [string trimleft $user -]
  250. }
  251.  
  252. set local_io [expr ($user_number==3)||$user2_islocal]
  253. if $local_io||($user_number==2) {
  254.     if 0==[info exists pid] {set pid [pid]}
  255.  
  256.     set userinfile /tmp/exp0.$pid
  257.     set useroutfile /tmp/exp1.$pid
  258. }
  259.  
  260. proc prompt1 {} {
  261.     return "kibitz[info level].[history nextid]> "
  262. }
  263.  
  264. set esc_match {}
  265. if {$allow_escape} {
  266.    set esc_match {
  267.       $escape_char {
  268.     send_user "\nto exit kibitz, enter: exit\n"
  269.     send_user "to suspend kibitz, press appropriate job control sequence\n"
  270.     send_user "to return to kibitzing, enter: return\n"
  271.     interpreter
  272.     send_user "returning to kibitz\n"
  273.       }
  274.    }
  275. }
  276.  
  277. proc prompt1 {} {
  278.     return "kibitz[info level].[history nextid]> "
  279. }
  280.  
  281. set timeout -1
  282.  
  283. # kibitzer executes following code
  284. if $user_number==2 {
  285.     # for readability, swap variables
  286.     set tmp $userinfile
  287.     set userinfile $useroutfile
  288.     set useroutfile $tmp
  289.  
  290.     if ![file readable $userinfile] {
  291.         send_user "Eh?  No one is asking you to kibitz.\n"
  292.         exit -1
  293.     }
  294.      spawn -open [open "|cat $catflags < $userinfile" "r"]
  295.     set userin $spawn_id
  296.  
  297.     spawn -open [open $useroutfile w]
  298.     set userout $spawn_id
  299.     # open will hang until other user's cat starts
  300.  
  301.     stty -echo raw
  302.     if $allow_escape {send_user "Escape sequence is $escape_printable\r\n"}
  303.  
  304.     # While user is reading message, try to delete other fifo
  305.     catch {exec rm -f $userinfile}
  306.  
  307.     eval interact $esc_match \
  308.         -output $userout \
  309.         -input $userin
  310.  
  311.     exit
  312. }
  313.  
  314. # only user_numbers 1 and 3 execute remaining code
  315.  
  316. proc abort {} {
  317.     global user_number
  318.  
  319.     # KABORT tells user_number 1 that user_number 3 has run into problems
  320.     # and is exiting, and diagnostics have been returned already
  321.     if $user_number==3 {send_user KABORT}
  322.     exit
  323. }
  324.  
  325. if $local_io {
  326.     proc mkfifo {f} {
  327.     if 0==[catch {exec mkfifo $f}] return        ;# POSIX
  328.     if 0==[catch {exec mknod $f p}] return
  329.     # some systems put mknod in wierd places
  330.     if 0==[catch {exec /usr/etc/mknod $f p}] return    ;# Sun
  331.     if 0==[catch {exec /etc/mknod $f p}] return    ;# AIX, Cray
  332.     puts "Couldn't figure out how to make a fifo - where is mknod?"
  333.     abort
  334.     }
  335.  
  336.     proc rmfifos {} {
  337.     global userinfile useroutfile
  338.     catch {exec rm -f $userinfile $useroutfile}
  339.     }
  340.  
  341.     trap {rmfifos; exit} {SIGINT SIGQUIT}
  342.  
  343.     # create 2 fifos to communicate with other user
  344.     mkfifo $userinfile
  345.     mkfifo $useroutfile
  346.     # make sure other user can access despite umask
  347.     exec chmod 666 $userinfile $useroutfile
  348.  
  349.     if $verbose {send_user "asking $user to type:  kibitz -$pid\n"}
  350.  
  351.     # can't use exec since write insists on being run from a tty!
  352.     set rc [catch {
  353.            system echo "Can we talk?  Run: \"kibitz -$pid\"" | \
  354.             /bin/write $user $tty
  355.         }
  356.     ]
  357.     if $rc {rmfifos;abort}
  358.  
  359.     spawn -open [open $useroutfile w]
  360.     set userout $spawn_id
  361.     # open will hang until other user's cat starts
  362.  
  363.     spawn -open [open "|cat $catflags < $userinfile" "r"]
  364.     set userin $spawn_id
  365.     catch {exec rm $userinfile}
  366. }
  367.  
  368. stty -echo raw
  369.  
  370. if $user_number==3 {
  371.     send_user "KDATA"    ;# this tells user_number 1 to send data
  372.  
  373.     interact {
  374.         -output $userout
  375.         -input $userin eof {
  376.             wait -i $userin
  377.             return -tcl
  378.         } -output $user_spawn_id 
  379.     }
  380. } else {
  381.     if $allow_escape {send_user "Escape sequence is $escape_printable\r\n"}
  382.  
  383.     if $noproc {
  384.         interact {
  385.             -output $userout
  386.             -input $userin eof {wait -i $userin; return}
  387.             -output $user_spawn_id
  388.         }
  389.     } else {
  390.         eval interact $esc_match {
  391.             -output $shell \
  392.             -input $userin eof {
  393.                 wait -i $userin
  394.                 close -i $shell
  395.                 return
  396.             } -output $shell \
  397.             -input $shell -output "$user_spawn_id $userout"
  398.         }
  399.         wait -i $shell
  400.     }
  401. }
  402.  
  403. if $local_io rmfifos
  404.